import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.crypto.SecretKey;
import org.apache.log4j.Logger;

public class Manager
{        
    private static final Logger log = Logger.getLogger(Manager.class);
    private ArrayList<ICompressor> compressorsList;
    private ArrayList<IWriter> writersList;
    private String work_direktory = "/home/tatyana/Documents/File_for_compressor/files/";
    private WorkWithFile file_work = new WorkWithFile(work_direktory);
    private ComponentList list = new ComponentList();
    private Query query = new Query();
    Manager()
    {
        log.info("Manager is started");
        log.info("Work direktory: " + work_direktory);
        this.compressorsList = list.getCompressorsList();
        this.writersList = list.getWritersList();
    }  
    public void WriteDataForFileFromDirectory(String directory)
    {
        log.info("Write data from directory: " + directory);
        File directory_ = new File(directory);            
        String files_list[] = directory_.list();
        OpenWriters();
        for(int i = 0; i < files_list.length; i++)
        {
            RegularExpression regex = new RegularExpression();
            regex.Split_Name_Extension(files_list[i]);
            log.debug("File from directory: " + files_list[i]);
            //String file_name = regex.getFileName();
            String type = regex.getFileType();      
            //long file_size = file_work.GetSizeFile(files_list[i]); 
            File f = file_work.createFile(files_list[i]);
            String content = new String(file_work.ReadFile(f));
//            Long size = new Long(content.length());
            Long size = file_work.GetSizeFile(f);
            log.debug("Files size: " + size);
            String language = "";
            log.debug("Files language: " + language);
            TFile file = new TFile(content, type, language, size);           
            WriteFileWithAllWriters(file);
            log.info("Write file with all writers");          
            ArchiveFileWithAllCompressors(file, f);
            log.info("Archive file with all compressors");
            EncryptFileWithAllEncryptionMethods(file, f);
            log.info("Encrypt file with all encryption methods");
        }
        CloseWriters();
    }
    public void WriteDataForFileFromDataBase()
    {     
        log.info("Write data from data base");
        List files = query.getFileFromTFile();
        OpenWriters();
        Iterator files_iterator = files.iterator();
        while(files_iterator.hasNext())
        {
            TFile file = (TFile)files_iterator.next();
            String content = file.getcontent();
            String file_name = "temp.txt";
            log.debug("create temp file: " + file_name);
            File f = file_work.createFile(file_name);
            file_work.WriteBinaryFile(content.getBytes(), f);
            ArchiveFileWithAllCompressors(file, f);
            log.info("Archive file with all compressors");
            EncryptFileWithAllEncryptionMethods(file, f);
            log.info("Encrypt file with all encryption methods");
            file_work.DeleteFile(f);
            log.info("Delete temp file");
        }
        CloseWriters();
    }
    public void WriteDataForRandomFileFromGenerator(String type, int count, int size, String language)
    {
        log.info("Write data for random file from generator");
        Generator generator = new Generator();
        OpenWriters();
        for(int i = 0; i < count; i++)
        {
            String text = generator.getRandomString(size, language);
//            Long text_size = new Long(text.length());
            String file_name = "random.txt";
            log.debug("Create random file :" + file_name);
            File f = file_work.createFile(file_name);
            file_work.WriteBinaryFile(text.getBytes(), f);
            Long file_size = file_work.GetSizeFile(f);
            log.debug("Size random file: " + file_size);
            TFile file = new TFile(text, type, language, file_size);
            WriteFileWithAllWriters(file);
            log.info("Write file with all writers");
            ArchiveFileWithAllCompressors(file, f);
            log.info("Archive file with all compressors");
            EncryptFileWithAllEncryptionMethods(file, f);
            log.info("Encrypt file with all encryption methods");
            file_work.DeleteFile(f);
            log.info("Delete random file");
        }
        CloseWriters();
    }
    public void WriteDataForSequenceFileFromGenerator(String type, int count, int size, String language, int count_letters)
    {
        log.info("Write data for sequence file from generator");
        Generator generator = new Generator();
        OpenWriters();
        for(int i = 0; i < count; i++)
        {
            String text = generator.getSequenceString(size, language, count_letters);
//            Long text_size = new Long(text.length());
            String file_name = "random.txt";
            log.debug("Create file: " + file_name);
            File f = file_work.createFile(file_name);
            file_work.WriteBinaryFile(text.getBytes(), f);
            long file_size = file_work.GetSizeFile(f);
            log.debug("Size sequence file: " + file_size);
            TFile file = new TFile(text, type, language, file_size);
            WriteFileWithAllWriters(file);
            log.info("Write file with all writers");
            ArchiveFileWithAllCompressors(file, f);
            log.info("Archive file with all compressors");
            EncryptFileWithAllEncryptionMethods(file, f);
            log.info("Encrypt file with all encryption methods");
            file_work.DeleteFile(f);
            log.info("Delete sequence file");
        }
        CloseWriters();
    }
    private void EncryptFileWithAllEncryptionMethods(TFile file, File f)
    { 
         ArrayList<String> crypto_algorithms_list = list.getCryptoAlgorithmsList();
         Iterator<String> crypto_algorithms_iterator = crypto_algorithms_list.iterator();
         while(crypto_algorithms_iterator.hasNext())
         {
             String crypto_algorithm_name = crypto_algorithms_iterator.next();
             log.debug("Encrypt file " + f.getName() + " with encryption methods: " + crypto_algorithm_name);
             EncryptFileWithAllMode(file, f, crypto_algorithm_name);
         }
    }
    private void EncryptFileWithAllMode(TFile file, File f, String crypto_algorithm_name)
    {
        ArrayList<String> encryption_modes_list = list.getEncryptsModeList();
        Iterator mode_list_iterator = encryption_modes_list.iterator();
        while(mode_list_iterator.hasNext())
        {
             String mode = (String)mode_list_iterator.next();
             log.debug("Encrypt mode: " +  mode);
             String crypto_algorithm = crypto_algorithm_name + "/" + mode + "/" + "PKCS5Padding";
             log.debug("Crypto algorithm name: " + crypto_algorithm);
             log.info("Generate secret key");
             SecretKey key = file_work.generateKey(crypto_algorithm_name);
             log.info("Encrypt file");
             byte[] crypto_text = file_work.EncryptFile(crypto_algorithm, key, f);
             File crypto_file = file_work.createFile(crypto_algorithm_name + f.getName());
             file_work.WriteBinaryFile(crypto_text, crypto_file);
             //file_work.DecryptFile(crypto_algorithm, key, crypto_text);
             long crypto_file_size = file_work.GetSizeFile(crypto_file); 
             log.debug("Size crypto file: " + crypto_file_size);
             log.info("Write crypto file with all writers");
             WriteCryptoFileWithAllWriters(file, crypto_algorithm_name, crypto_file_size, mode);
             log.info("Archive crypto file with all compressors");
             ArchiveCryptoFilesWithAllCompressors(crypto_file);
             log.info("Delete crypto file " + crypto_file.getName());
             file_work.DeleteFile(crypto_file);
        }
    }
    private void ArchiveFileWithAllCompressors(TFile file, File f)
    {
         Iterator<ICompressor> compressor_iterator = compressorsList.iterator();
         log.debug("Archive file with all compressors");
         while(compressor_iterator.hasNext())
         {
             ICompressor compressor = compressor_iterator.next();
             log.debug("Archive file " + f.getName() + " with compressor: " + compressor.getName());
             TreeMap compression_levels_list = compressor.getCompressionLevelsList();   
             ArchiveFileWithAllCompressionLevels(file, f, compressor, compression_levels_list);
         }
    }
    private void ArchiveFileWithAllCompressionLevels(TFile file, File f, ICompressor compressor, TreeMap compression_levels_list)
    {        
        Iterator compression_levels_iterator = compression_levels_list.entrySet().iterator();
        while(compression_levels_iterator.hasNext())
        {
             Map.Entry entry = (Map.Entry)compression_levels_iterator.next();
             String indiv_compression_level = (String)entry.getValue();
             String compression_level = (String)entry.getKey();
             log.debug("Archive level: " + compression_level);
             String command_compression = compressor.getCommandCompression(work_direktory, f.getName(), indiv_compression_level);
             log.debug("Command: " + command_compression);
             file_work.PressFile(command_compression);
             String compressor_name = compressor.getName();
             String compressor_extension = compressor.getExtension();
             File arch_file = file_work.createFile(f.getName() + compressor_extension);
             log.debug("Create archive file: " + arch_file.getName());
             long size = file_work.GetSizeFile(arch_file);
             log.debug("Size archive file: " + size);
             int ratio = file_work.CompressionRatio(f, arch_file);
             log.debug("Ratio archive file: " + ratio);
             long time = file_work.TimeCompression();
             log.debug("Time archive file: " + time);
             log.debug("Delete file: " + arch_file.getName());
             file_work.DeleteFile(arch_file);
             WriteArchiveFileWithAllWriters(file, compressor_name, size, ratio, time, compression_level);  
        }
    }
    private void ArchiveCryptoFilesWithAllCompressors(File crypto_file)
    {
         Iterator<ICompressor> compressor_iterator = compressorsList.iterator();
         while(compressor_iterator.hasNext())
         {
             ICompressor compressor = compressor_iterator.next();
             log.debug("Compressor: " + compressor.getName());
             String compression_level = (String)compressor.getCompressionLevelsList().get("medium");
             log.debug("Compression level: " + compression_level);
             String command_compression = compressor.getCommandCompression(work_direktory, crypto_file.getName(), compression_level);
             log.debug("Command: " + command_compression);
             log.info("Press file");
             file_work.PressFile(command_compression);
             String compressor_name = compressor.getName();
             String compressor_extension = compressor.getExtension();
             String archive_crypto_file_name = crypto_file.getName() + compressor_extension;
             log.info("Create crypto file: " + archive_crypto_file_name);
             File archive_crypto_file = file_work.createFile(archive_crypto_file_name);
             long size_crypto_file = file_work.GetSizeFile(crypto_file);
             log.debug("Size crypto file: " + size_crypto_file);
             int ratio = file_work.CompressionRatio(crypto_file, crypto_file);
             log.debug("Ratio crypto file: " + ratio);
             long time = file_work.TimeCompression();
             log.debug("Time crypto file: " + time);
             file_work.DeleteFile(crypto_file);
             log.info("Delete crypto file: " + archive_crypto_file_name);
             WriteArchiveCryptoFileWithAllWriters(compressor_name, size_crypto_file, ratio, time);          
             log.info("Write archive crypto file with all writers");
         }
    }
    private void OpenWriters()
    {
        Iterator<IWriter> writer_iterator = writersList.iterator();
        log.info("Open writers");
         while(writer_iterator.hasNext())
         {
             IWriter writer = writer_iterator.next();
             writer.OpenWriter();       
         }
    }
    private void CloseWriters()
    {
        log.info("Close writers");
        Iterator<IWriter> writer_iterator = writersList.iterator();
         while(writer_iterator.hasNext())
         {
             IWriter writer = writer_iterator.next();
             writer.CloseWriter();       
         }
    }
    private void WriteFileWithAllWriters(TFile file)
    {
         Iterator<IWriter> writer_iterator = writersList.iterator();
         
         while(writer_iterator.hasNext())
         {
             IWriter writer = writer_iterator.next();
             writer.WriteFile(file);     
             log.debug("Write file with writer " + writer);
         }
    }
    private void WriteArchiveFileWithAllWriters(TFile file, String compressor_name, long arch_file_size, int ratio, long time, String compression_level)
    {
        Iterator<IWriter> writer_iterator = writersList.iterator();
         while(writer_iterator.hasNext())
         {
             IWriter writer = writer_iterator.next();
             writer.WriteArchiveFile(file, compressor_name, arch_file_size, ratio, time, compression_level);   
             log.debug("Write archive file with writer: " + writer);
         }
    }
    private void WriteCryptoFileWithAllWriters(TFile file, String crypto_algorithm, long crypto_file_size, String mode)
    {
        Iterator<IWriter> writer_iterator = writersList.iterator();
         while(writer_iterator.hasNext())
         {
             IWriter writer = writer_iterator.next();
             writer.WriteCryptoFile(file, crypto_algorithm, crypto_file_size, mode);
             log.debug("Write crypto file with writer: " + writer);
         }
    }
    private void WriteArchiveCryptoFileWithAllWriters(String compressor_name, long archive_crypto_file_size, int ratio, long time)
    {
        Iterator<IWriter> writer_iterator = writersList.iterator();
         while(writer_iterator.hasNext())
         {
             IWriter writer = writer_iterator.next();
             writer.WriteArchiveCryptoFile(compressor_name, archive_crypto_file_size, ratio, time);       
             log.debug("Write archive crypto file with writer: " + writer);
         }
    }
    public void createChartForFile(FrameChart frame_chart, String absciss_label, String ordinate_label, 
                            Long size, String type, String language, 
                            String archive_level)
    {
        Iterator<ICompressor> compressor_iterator = compressorsList.iterator();
        CoordinateAxis coordinate_axis = new CoordinateAxis(absciss_label, ordinate_label);
         while(compressor_iterator.hasNext())
         {
             ICompressor compressor = compressor_iterator.next();
             String compressor_name = compressor.getName();
             List data = coordinate_axis.getOrdinateDataForFile(size, type, language, archive_level, compressor_name);
             List columns = coordinate_axis.getAbscissData();          
            frame_chart.addLine(compressor_name, columns, data);
         }
    }
    public void createChartForCryptoFile(FrameChart frame_chart, String absciss_label, String ordinate_label, 
                                         Long size, String type, String language, String compressor, String encrypt_mode)
    {
         CoordinateAxis coordinate_axis = new CoordinateAxis(absciss_label, ordinate_label);
         ArrayList<String> crypto_algorithms_list = list.getCryptoAlgorithmsList();
         Iterator<String> crypto_algorithms_iterator = crypto_algorithms_list.iterator();
         while(crypto_algorithms_iterator.hasNext())
         {
             String crypto_algorithm_name = crypto_algorithms_iterator.next();         
             List data = coordinate_axis.getOrdinateDataForCryptoFile(size, type, language, compressor, 
                                                                         crypto_algorithm_name, encrypt_mode);
             List columns = coordinate_axis.getAbscissData();
             frame_chart.addLine(crypto_algorithm_name, columns, data);
         }
    }
}